package pers.qianyu.module.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import pers.qianyu.module.core.domain.system.converter.SysResourceConverter;
import pers.qianyu.module.core.domain.system.converter.SysRoleConverter;
import pers.qianyu.module.core.domain.system.dto.SysRoleResourceDTO;
import pers.qianyu.module.core.domain.system.entity.SysResourcePO;
import pers.qianyu.module.core.domain.system.entity.SysRolePO;
import pers.qianyu.module.core.domain.system.entity.SysRoleResourcePO;
import pers.qianyu.module.core.domain.system.entity.SysUserRolePO;
import pers.qianyu.module.core.domain.system.vo.SysResourceVO;
import pers.qianyu.module.core.domain.system.vo.SysRoleVO;
import pers.qianyu.module.system.dao.SysRoleResourceDao;
import pers.qianyu.module.system.dao.SysUserRoleDao;
import pers.qianyu.module.system.exception.SysErrorCodeEnum;
import pers.qianyu.module.system.exception.SysException;
import pers.qianyu.module.system.listener.events.SysUserInfoListUpdatedEvent;
import pers.qianyu.module.system.service.SysRoleResourceService;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author mizzle rain
 * @date 2021-05-03 22:41
 */
@Service("sysRoleResourceService")
public class SysRoleResourceServiceImpl
        extends ServiceImpl<SysRoleResourceDao, SysRoleResourcePO>
        implements SysRoleResourceService {
    @Autowired
    private SysRoleResourceDao sysRoleResourceDao;
    @Autowired
    private SysResourceConverter sysResourceConverter;
    @Autowired
    private SysRoleConverter sysRoleConverter;
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private SysUserRoleDao sysUserRoleDao;

    @Override
    public List<SysResourceVO> queryByRoleId(Long roleId) {
        List<SysResourcePO> sysResourcePOS = sysRoleResourceDao.selectResourcesByRoleId(roleId);
        if (CollUtil.isEmpty(sysResourcePOS)) {
            return new ArrayList<>();
        }
        return sysResourcePOS.stream()
                .map(sysResourceConverter::convertToVO)
                .collect(Collectors.toList());
    }

    @Override
    public List<SysRoleVO> queryByResourceId(Long resourceId) {
        List<SysRolePO> sysRolePOS = sysRoleResourceDao.selectRoleByResourceId(resourceId);
        if (CollUtil.isEmpty(sysRolePOS)) {
            return new ArrayList<>();
        }
        return sysRoleConverter.convertToVOS(sysRolePOS);
    }

    @Override
    public void insRoleResource(SysRoleResourceDTO sysRoleResourceDTO) {
        SysRoleResourcePO sysRoleResourcePO = new SysRoleResourcePO();
        sysRoleResourcePO.setRoleId(sysRoleResourceDTO.getRoleId());
        sysRoleResourcePO.setResourceId(sysRoleResourceDTO.getResourceId());
        if (Objects.isNull(sysRoleResourceDao.selectOne(new QueryWrapper<>(sysRoleResourcePO)))) {
            sysRoleResourceDao.insert(sysRoleResourcePO);
        }

        // 更新Redis中用户信息
        publishSysUserInfoListUpdatedEvent(sysRoleResourceDTO.getRoleId());
    }

    @Override
    public void delRoleResource(SysRoleResourceDTO sysRoleResourceDTO) {
        SysRoleResourcePO sysRoleResourcePO = new SysRoleResourcePO();
        sysRoleResourcePO.setRoleId(sysRoleResourceDTO.getRoleId());
        sysRoleResourcePO.setResourceId(sysRoleResourceDTO.getResourceId());
        QueryWrapper<SysRoleResourcePO> wrapper = new QueryWrapper<>(sysRoleResourcePO);
        int row = sysRoleResourceDao.delete(wrapper);
        if (row < 1) {
            throw new SysException(SysErrorCodeEnum.INVALID_PARAMETERS);
        }

        // 更新Redis中用户信息
        publishSysUserInfoListUpdatedEvent(sysRoleResourceDTO.getRoleId());
    }

    /**
     * 发布更新用户信息事件
     *
     * @param roleId 角色 ID
     */
    private void publishSysUserInfoListUpdatedEvent(Long roleId) {
        SysUserRolePO sysUserRolePO = new SysUserRolePO();
        sysUserRolePO.setRoleId(roleId);
        QueryWrapper<SysUserRolePO> wp = new QueryWrapper<>();
        wp.select("user_id");
        List<SysUserRolePO> sysUserRolePOS = sysUserRoleDao.selectList(wp);
        applicationContext.publishEvent(new SysUserInfoListUpdatedEvent(this,
                sysUserRolePOS.stream()
                        .map(SysUserRolePO::getUserId)
                        .collect(Collectors.toList())
        ));
    }
}
